package framework.spatial;

import java.awt.Graphics;
import java.awt.Point;

/**
 *
 * @author Lukáš Marek
 */
public class FRDSpatialGRectangle extends FRDSpatialGItem
{
	private Point p1, p2;
	
	public FRDSpatialGRectangle()
	{
		p1 = new Point();
		p2 = new Point();
	}
	
	public void setLocation(Point p1, Point p2)
	{
		this.p1.setLocation(p1);
		this.p2.setLocation(p2);
	}
	
	public Point[] getLocation()
	{
		Point ret[] = new Point[2];
		ret[0] = p1;
		ret[1] = p2;
		return ret;
	}
	
	@Override
	public void setPoints(Point p1, Point p2)
	{		
		this.p1.setLocation(mapPoint(p1));
		this.p2.setLocation(mapPoint(p2));
	}
	
	@Override
	public boolean addPoints(Point p1, Point p2)
	{
		if (p1.distance(p2) < 5)
			return false;
		else
		{
			this.p1.setLocation(mapPoint(p1));
			this.p2.setLocation(mapPoint(p2));
			return true;
		}
	}

	@Override
	public void draw(Graphics g)
	{
		if (selected)
			g.setColor(SelectedColor);
		else
			g.setColor(defaultColor);
		
		Point p = new Point();
		p.x = Math.min(p1.x, p2.x);
		p.y = Math.min(p1.y, p2.y);
		p = showPoint(p);
		Point size = showSize(new Point(Math.abs(p1.x - p2.x), Math.abs(p1.y - p2.y)));
		g.fillRect(p.x, p.y, size.x, size.y);
	}
	
	@Override
	public void drawEdit(Graphics g, Point pt1, Point pt2)
	{
		g.setColor(editColor);
		Point mp1 = null;
		Point p;
		Point mp2 = mapPoint(pt2);
		
		Point size = new Point(Math.abs(p1.x - p2.x), Math.abs(p1.y - p2.y));
		Point lt = new Point(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y));
		Point rt = new Point(lt.x + size.x, lt.y);
		Point lb = new Point(lt.x, lt.y + size.y);
		Point rb = new Point(lt.x + size.x, lt.y + size.y);

		if (near(mapPoint(pt1), lt))
			mp1 = new Point(rb);
		else if (near(mapPoint(pt1), rt))
			mp1 = new Point(lb);
		else if (near(mapPoint(pt1), lb))
			mp1 = new Point(rt);
		else if (near(mapPoint(pt1), rb))
			mp1 = new Point(lt);
		else if (undermouse(pt1))
		{
			p = new Point(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y));
			p = showPoint(p);
			size = showSize(new Point(Math.abs(p1.x - p2.x), Math.abs(p1.y - p2.y)));
			g.fillRect(p.x + (pt2.x - pt1.x), p.y + (pt2.y - pt1.y), size.x, size.y);
		}
			
		if (mp1 != null)
		{
			p = new Point(Math.min(mp1.x, mp2.x), Math.min(mp1.y, mp2.y));
			p = showPoint(p);
			size = showSize(new Point(Math.abs(mp1.x - mp2.x), Math.abs(mp1.y - mp2.y)));
			g.fillRect(p.x, p.y, size.x, size.y);
		}
	}
	
	@Override
	public void saveEdit(Point pt1, Point pt2)
	{
		Point mp2 = mapPoint(pt2);
		Point size = new Point(Math.abs(p1.x - p2.x), Math.abs(p1.y - p2.y));
		Point lt = new Point(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y));
		Point rt = new Point(lt.x + size.x, lt.y);
		Point lb = new Point(lt.x, lt.y + size.y);
		Point rb = new Point(lt.x + size.x, lt.y + size.y);
		if (near(mapPoint(pt1), lt))
		{
			if (p1.x < p2.x) p1.x = mp2.x;
			else p2.x = mp2.x;
			if (p1.y < p2.y) p1.y = mp2.y;
			else p2.y = mp2.y;
		}
		else if (near(mapPoint(pt1), rt))
		{
			if (p1.x > p2.x) p1.x = mp2.x;
			else p2.x = mp2.x;
			if (p1.y < p2.y) p1.y = mp2.y;
			else p2.y = mp2.y;
		}
		else if (near(mapPoint(pt1), lb))
		{
			if (p1.x < p2.x) p1.x = mp2.x;
			else p2.x = mp2.x;
			if (p1.y > p2.y) p1.y = mp2.y;
			else p2.y = mp2.y;
		}
		else if (near(mapPoint(pt1), rb))
		{
			if (p1.x > p2.x) p1.x = mp2.x;
			else p2.x = mp2.x;
			if (p1.y > p2.y) p1.y = mp2.y;
			else p2.y = mp2.y;
		}
		else if (undermouse(pt1))
		{
			Point p = mapPoint(pt1);			
			this.p1.x += mp2.x - p.x;
			this.p1.y += mp2.y - p.y;
			this.p2.x += mp2.x - p.x;
			this.p2.y += mp2.y - p.y;
		}
	}
	
	@Override
	public boolean undermouse(Point _p)
	{
		int rz = (selected) ? (int)(10/back.getScale()*back.getZoom()) : 0;
		Point left = new Point();
		left.x = Math.min(p1.x, p2.x) - rz;
		left.y = Math.min(p1.y, p2.y) - rz;
		Point size = new Point(Math.abs(p1.x - p2.x) + rz, Math.abs(p1.y - p2.y) + rz);
		Point p = mapPoint(_p);
		return ((left.x <= p.x) && (p.x <= (left.x + size.x)) && (left.y <= p.y) && (p.y <= (left.y + size.y)));
	}
	
	/**
	 * Zjisteni blizkosti dvou bodu
	 * @param _p prvni bod
	 * @param p druhy bod
	 * @return true pokud sou body blizko
	 */
	protected boolean near(Point _p, Point p)
	{
		double zoom = back.getZoom();
		return (p.distance(_p) < (10*4/zoom));
	}
	
	/**
	 * prepocita bod z mapy na bod v panelu
	 * @param pt bod
	 * @return 
	 */
	private Point showPoint(Point pt)
	{
		double scale = back.getScale();
		Point zoomLoc = back.getPosition();
		double zoom = back.getZoom();
		double df = scale / zoom;
		Point ret = new Point();
		ret.x = (int)((pt.x - zoomLoc.x) / df);
		ret.y = (int)((pt.y - zoomLoc.y) / df);
		return ret;
	}
	
	/**
	 * prepocita velikost z mapy na velikost v panelu
	 * @param pt
	 * @return 
	 */
	private Point showSize(Point pt)
	{
		double scale = back.getScale();
		double zoom = back.getZoom();
		double df = scale / zoom;
		Point ret = new Point();
		ret.x = (int)(pt.x / df);
		ret.y = (int)(pt.y / df);
		return ret;
	}
	
	/**
	 * prepocita bod z panelu na bod v mape
	 * @param pt
	 * @return 
	 */
	private Point mapPoint(Point pt)
	{
		double scale = back.getScale();
		Point zoomLoc = back.getPosition();
		double zoom = back.getZoom();
		double df = scale / zoom;
		Point ret = new Point();
		ret.x = (int)(pt.x * df) + zoomLoc.x;
		ret.y = (int)(pt.y * df) + zoomLoc.y;
		return ret;
	}
}
